/*
 * Copyright (C) 2009 Dimitrios C. Michalakos
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import com.cs.util.db.Database;
import com.cs.util.db.DatabaseEngineEnum;
import com.cs.util.http.AuthBasicHeader;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 *
 * @author dimitris@jmike.gr
 */
public class Meta {

    private final DatabaseEngineEnum dbEngine;
    private final String dbHost;
    private final int dbPort;
    private final String dbSchema;
    private final String dbUsername;
    private final String dbPassword;

    /**
     * Constructs a new Meta.
     * @param dbType
     * @param dbHost
     * @param dbPort
     * @param dbSchema
     * @param dbUsername
     * @param dbPassword
     */
    public Meta(
            DatabaseEngineEnum dbType,
            String dbHost,
            int dbPort,
            String dbSchema,
            String dbUsername,
            String dbPassword) {
        this.dbEngine = dbType;
        this.dbHost = dbHost;
        this.dbPort = dbPort;
        this.dbSchema = dbSchema;
        this.dbUsername = dbUsername;
        this.dbPassword = dbPassword;
    }

    /**
     * Returns the engine type of the meta database.
     * @return
     */
    public DatabaseEngineEnum getDbEngineEnum() {
        return dbEngine;
    }

    /**
     * Returns the host of the meta database.
     * @return
     */
    public String getDbHost() {
        return dbHost;
    }

    /**
     * Returns the port of the meta database.
     * @return
     */
    public int getDbPort() {
        return dbPort;
    }

    /**
     * Returns the username of the meta database.
     * @return
     */
    public String getDbUsername() {
        return dbUsername;
    }

    /**
     * Returns the password of the meta database.
     * @return
     */
    public String getDbPassword() {
        return dbPassword;
    }

    /**
     * Returns a new meta database.
     * @return
     * @throws java.sql.SQLException
     */
    public Database getDatabase() throws SQLException {
        return new Database(dbEngine, dbHost, dbPort, dbSchema, dbUsername, dbPassword);
    }

    /**
     * Finds the designated account in meta database and returns its id.
     * @param accountName the name of the account.
     * @return  -1 if account cannot be found in database.
     */
    public int getAccountId(String accountName) {
        /* initialize account id */
        int accountId = -1;
        /* find user in database and get her account id */
        try {
            Database db = this.getDatabase();
            PreparedStatement ps = db.getPreparedStatement("SELECT `id` FROM `account`WHERE `name` = ?;");
            ps.setString(1, accountName);//set account name
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                accountId = rs.getInt("id");//set id
            }
            rs.close();
            ps.close();
            db.close();
        } catch (SQLException ex) {
            /* ignore the error */
        }
        /* return account id */
        return accountId;
    }

//    /**
//     * Finds the designated user in database and returns her account id.
//     * @param userName the name of the user.
//     * @param password the password of the user.
//     * @param accountName the name of the user's account.
//     * @return -1 if user is not matched.
//     */
//    public int getAccountId(String userName, String password, String accountName) {
//        /* initialize account id */
//        int accountId = -1;
//        /* find user in database and get her account id */
//        try {
//            Database db = this.getDatabase();
//            PreparedStatement ps = db.getPreparedStatement("SELECT `user`.accountid FROM `user` INNER JOIN `account` ON `user`.accountid = `account`.id WHERE `account`.name = ? AND `user`.name = ? AND `user`.password = ?;");
//            ps.setString(1, accountName);//set account name
//            ps.setString(2, userName);//set user name
//            ps.setString(3, password);//set user password
//            ResultSet rs = ps.executeQuery();
//            if (rs.next()) {
//                accountId = rs.getInt("accountid");//set account id
//            }
//            rs.close();
//            ps.close();
//            db.close();
//        } catch (DatabaseNotConnectedException ex) {
//            /* ignore the error */
//        } catch (SQLException ex) {
//            /* ignore the error */
//        }
//        /* return the account id */
//        return accountId;
//    }
//
//    /**
//     * Parses the specified authHeader, finds the designated user in database and returns her account id.
//     * @param authHeader authorization (BASIC) header containing the user's name and password.
//     * @param accountName the name of the user's account.
//     * @return -1 if user is not matched.
//     */
//    public int getAccountId(String authHeader, String accountName) {
//        /* parse authorization (basic) header */
//        AuthBasicParser auth = new AuthBasicParser(authHeader);//parse authorization header
//        /* return the account id */
//        return getAccountId(auth.getUserName(), auth.getPassword(), accountName);
//    }
    /**
     * Indicates whether the designated user exists in meta database.
     * @param userName the name of the user.
     * @param password the password of the user.
     * @param accountId the id of the user's account.
     * @return true if user exists, false if not.
     */
    public boolean existsUser(String userName, String password, int accountId) {
        /* initialize exists */
        boolean exists = false;
        /* find user in database and get her account id */
        try {
            Database db = this.getDatabase();
            PreparedStatement ps = db.getPreparedStatement("SELECT `id` FROM `user` WHERE `accountid` = ? AND `name` = ? AND `password` = ?;");
            ps.setInt(1, accountId);//set account id
            ps.setString(2, userName);//set user name
            ps.setString(3, password);//set user password
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                exists = true;//set exists
            }
            rs.close();
            ps.close();
            db.close();
        } catch (SQLException ex) {
            /* ignore the error */
        }
        /* return exists */
        return exists;
    }

    /**
     * Parses the specified authHeader, indicates whether the designated user exists in meta database.
     * @param authHeader authorization (BASIC) header containing the user's name and password.
     * @param accountId the id of the user's account.
     * @return true if user exists, false if not.
     */
    public boolean existsUser(String authHeader, int accountId) {
        /* parse authorization (basic) header */
        AuthBasicHeader auth = new AuthBasicHeader(authHeader);//parse authorization header
        /* return exists */
        return existsUser(auth.getUserName(), auth.getPassword(), accountId);
    }

    /**
     * Finds the designated database's connection properties and returns a new Database object.
     * @param dbName the name of the database to be returned.
     * @param accountId the id of the database's account.
     * @return null if database does not belong to the specified account or does not exist in meta database.
     * @throws SQLException 
     */
    public Database getDatabase(String dbName, int accountId) throws SQLException {
        Database ndb = null;
        /* find dbname in database and set new database */
        Database db = this.getDatabase();
        PreparedStatement ps = db.getPreparedStatement("SELECT `type`, `host`, `port`, `schema`, `username`, `password` FROM `database` WHERE `accountid` = ? AND `name` = ?;");
        ps.setInt(1, accountId);//set account id
        ps.setString(2, dbName);//set database name
        ResultSet rs = ps.executeQuery();
        if (rs.next()) {
            final DatabaseEngineEnum type = DatabaseEngineEnum.valueOf(rs.getString("type"));
            final String host = rs.getString("host");
            final int port = rs.getInt("port");
            final String schema = rs.getString("schema");
            final String username = rs.getString("username");
            final String password = rs.getString("password");
            ndb = new Database(type, host, port, schema, username, password);
        }
        rs.close();
        ps.close();
        db.close();
        /* return new database */
        return ndb;
    }
}
